package wzq.cn.wuziqi.core;

import wzq.cn.wuziqi.RC;
import wzq.cn.wuziqi.algorithm.ScoreTable;
import wzq.cn.wuziqi.model.ChessBoard;
import wzq.cn.wuziqi.model.PointU;
import wzq.cn.wuziqi.utils.LogUtils;

/**
 * Created by xiawei on 15/10/26.
 */
public class AI {


    public PointU[][] mResults;

    private int deep = 0;
    private int N_STEP = 10;


    /**
     * 当前得分最高的位置
     */
    public PointU otherMaxScoreStep = new PointU();
    public PointU myMaxScoreStep = new PointU();
    public long mMaxScore = 0;
    private int winNumber = 0;
    private int level = 1;
    private ChessBoard.SIDE mSide;
    private ChessBoard.SIDE otherSide;

    private void reset() {
        deep = 0;
        myMaxScoreStep.score = 0;
        myMaxScoreStep.belong = ChessBoard.SIDE.NONE;
        myMaxScoreStep.x = PointU.P_UNUSE;
        myMaxScoreStep.y = PointU.P_UNUSE;

        otherMaxScoreStep.score = 0;
        otherMaxScoreStep.belong = ChessBoard.SIDE.NONE;
        otherMaxScoreStep.x = PointU.P_UNUSE;
        otherMaxScoreStep.y = PointU.P_UNUSE;

        mMaxScore = 0;
        ScoreTable.clear();
    }

    /**
     * 解析下一步的棋子
     *
     * @param results   当前棋盘的结果
     * @param winNumber 连了几个就赢
     * @return 下一步的位置
     */
    public PointU getNextStep(PointU[][] results, int winNumber) {


        reset();
        this.winNumber = winNumber;
        this.mResults = results;


        ChessBoard.SIDE mSide = getCurrentSide(results);
        //(otherSide== ChessBoard.SIDE.BLACK)? ChessBoard.SIDE.WHITE: ChessBoard.SIDE.BLACK;
        ChessBoard.SIDE otherSide = ((mSide == ChessBoard.SIDE.BLACK) ? ChessBoard.SIDE.WHITE : ChessBoard.SIDE.BLACK);
        int sizeRow = this.mResults.length;
        int sizeColum = this.mResults[0].length;
        ScoreTable mScoreTable = ScoreTable.get(mSide, sizeRow, sizeColum);
        ScoreTable otherScoreTable = ScoreTable.get(otherSide, sizeRow, sizeColum);
        long s = System.currentTimeMillis();
        for (int i = 0; i < sizeRow; i++) {
            for (int j = 0; j < sizeColum; j++) {
                //如果改位置有棋子，则忽略
                if (mResults[i][j].belong == ChessBoard.SIDE.NONE) {
                    //在某个位置下一个棋子，然后计算该棋子此时的分数
                    //没次下一个棋子，都计算黑白双方此时的得分
                    put(i, j, mSide);
                    /**
                     * 重新计算整个局面的最高得分
                     */
                    mScoreTable.tables[i][j] = calScore(i, j, mSide, sizeRow, sizeColum);
                    //新的数据比旧的数据多，则替换
                    checkMaxScore(mScoreTable.tables[i][j], i, j, myMaxScoreStep);

                    put(i, j, otherSide);
                    otherScoreTable.tables[i][j] = calScore(i, j, otherSide, sizeRow, sizeColum);
                    //新的数据比旧的数据多，则替换
                    checkMaxScore(otherScoreTable.tables[i][j], i, j, otherMaxScoreStep);

                    del(i, j);
                }
            }
        }
        LogUtils.d("e=" + (System.currentTimeMillis() - s));
        LogUtils.d("next=" + mScoreTable.toString());
        LogUtils.d("onext=" + otherScoreTable.toString());
        LogUtils.d("m=", myMaxScoreStep.toString());
        LogUtils.d("o=" + otherMaxScoreStep.toString());

        return getValuablePointU();

    }

    /**
     * 返回下一步的位置
     *
     * @return
     */
    private PointU getValuablePointU() {


        long myScore = myMaxScoreStep.score;
        long oppScore = otherMaxScoreStep.score;

        // 1 如果我是5连，我走！
        if (myScore >= RC.SCORES[winNumber]) {
            return myMaxScoreStep;
        }
        //对手5连。你走着！
        if (oppScore >= RC.SCORES[winNumber]) {
            return otherMaxScoreStep;
        }

        //如果对面是4连，我也是4连,我走！
//            if(oppScore>=RC.SCORES[winNumber-1] && myScore>=RC.SCORES[winNumber-1]){
//                return myMaxScoreStep;
//            }

        return myScore > oppScore * 0.9 ? myMaxScoreStep : otherMaxScoreStep;
    }


    /**
     * 根据盘面上的棋子，得到哪边开始走
     *
     * @param results
     * @return
     */
    private ChessBoard.SIDE getCurrentSide(PointU[][] results) {

        int sizeWhite = 0;
        int sizeBlack = 0;
        int sizeRow = results.length;
        int sizeColum = results[0].length;

        for (int i = 0; i < sizeRow; i++) {
            for (int j = 0; j < sizeColum; j++) {
                if (results[i][j].belong == ChessBoard.SIDE.BLACK) {
                    sizeBlack++;
                } else if (results[i][j].belong == ChessBoard.SIDE.WHITE) {
                    sizeWhite++;
                }
            }
        }
        return (sizeBlack > sizeWhite) ? ChessBoard.SIDE.WHITE : ChessBoard.SIDE.BLACK;
    }

    /**
     * 检测是否比目前的更大
     *
     * @param cMax
     * @param i
     * @param j
     */
    private void checkMaxScore(long cMax, int i, int j, PointU p) {
        if (cMax > p.score) {
            p.x = i;
            p.y = j;
            p.score = cMax;
        }
//        else if (cMax == p.score) {
//            //如果相等，就交给天意
//            //防止每次都相同
//            boolean change = System.currentTimeMillis() % 2 == 0;
//            if (change) {
//                p.x = i;
//                p.y = j;
//                p.score = cMax;
//            }
//        }
    }

    /**
     * 计算这个点的得分
     *
     * @param i
     * @param j
     * @param mSide
     * @param sizeRow
     * @param sizeColum
     */
    private long calScore1(int i, int j, ChessBoard.SIDE mSide, int sizeRow, int sizeColum) {
        long maxScore = -1;
        int sizeDirects = RC.directs.length;
        for (int k = 0; k < sizeDirects; k++) {
            deep = verifyDirect(i, j, winNumber, RC.directs[k], sizeRow, sizeColum, mSide);
            if (maxScore < RC.SCORES[deep / N_STEP]) {
                maxScore = RC.SCORES[deep / N_STEP];
                if (deep % N_STEP != 0) {
                    maxScore += maxScore / 2;
                }
            }
            // LogUtils.d("maxScore="+maxScore +",side ="+mSide);
            deep = 0;
        }
        return maxScore;
    }

    /**
     * 计算这个点的得分,更全面的
     *
     * @param i
     * @param j
     * @param mSide
     * @param sizeRow
     * @param sizeColum
     */
    private long calScore(int i, int j, ChessBoard.SIDE mSide, int sizeRow, int sizeColum) {
        long maxScore = 0;
        long tempmax = 0;
        if (this.level == 0) {
            maxScore = calScore1(i, j, mSide, sizeRow, sizeColum);
        } else if (this.level == 1) {
            int sizeDirects = RC.directs.length;
            for (int m = 0; m < sizeColum; m++) {
                for (int n = 0; n < sizeRow; n++) {
                    PointU pmn = mResults[m][n];
                    //空白参与计分
                    // if(pmn.belong == ChessBoard.SIDE.NONE) {

                    for (int k = 0; k < sizeDirects; k++) {
                        deep = verifyDirect(m, n, winNumber, RC.directs[k], sizeRow, sizeColum, mSide);
                        //2 连子以上参与累计分数
                        tempmax = calScoreByDeep(deep);
                        deep = 0;
                    }
                    /**
                     * 计算出某个点最高分数
                     */
                    if (tempmax > maxScore) {
                        maxScore = tempmax;
                    }
                    tempmax = 0;
                    // }
                }
            }
        }
        return maxScore;
    }

    private long calScoreByDeep(int deep) {
        long tempmax = 0;
        int d = deep/N_STEP;
        tempmax += RC.SCORES[d];
        if (deep % N_STEP != 0) {
            //额外积分，以当前最高积分为主
            tempmax += (deep % N_STEP) * RC.SCORES[d];
        }
        return tempmax;
    }


    /**
     * @param side1 src
     * @param side2 next
     * @return
     */
    private boolean isBelong(ChessBoard.SIDE side1, ChessBoard.SIDE side2, ChessBoard.SIDE realSide) {
        if (side1 == side2 && side1 == realSide) {
            return true;
        }
        return false;
    }

    /**
     * 是否需要比较下一个
     *
     * @param sizeRow
     * @param sizeClo
     * @param psrc
     * @param nextX
     * @param nexty
     * @return
     */
    private int verfyNext(int sizeRow, int sizeClo, PointU psrc, int nextX, int nexty, ChessBoard.SIDE side) {
        if ((nextX < sizeRow) && (nexty < sizeClo) && (nextX >= 0) && (nexty >= 0)) {
            PointU pnext = mResults[nextX][nexty];
            if (isBelong(psrc.belong, pnext.belong, side)) {
                return SAME;
            } else {
                /**
                 *  如果有连子，并且有一头是空白的，则积分额外增加
                 */
                if (((deep / N_STEP) > 2) && (pnext.belong == ChessBoard.SIDE.NONE)) {
                    return EXTRA_SAME;
                }
            }
        }
        return DISABLED;
    }


    public int DISABLED = 0;
    public int SAME = 1;
    public int EXTRA_SAME = N_STEP / 2 + 1;

    private int verifyDirect(int x, int y, int number, ChessBoard.DIRECT d, int sizeRow, int sizeClo, ChessBoard.SIDE side) {
        deep += N_STEP;

        PointU psrc = mResults[x][y];

        int nextX = x;
        int nexty = y;

        int available = 0;

        if (d == ChessBoard.DIRECT.BUTTOM) {
            // Y+1
            nextX = x;
            nexty = y + 1;
            available = (sizeRow - nexty);


        } else if (d == ChessBoard.DIRECT.BUTTON_LEFT) {
            // x+1 y+1
            nextX = x - 1;
            nexty = y + 1;
            available = Math.min(nextX, (sizeClo - nexty));

        } else if (d == ChessBoard.DIRECT.LEFT) {
            nextX = x - 1;
            nexty = y;
            available = nextX;
        } else if (d == ChessBoard.DIRECT.LEFT_TOP) {
            nextX = x - 1;
            nexty = y - 1;

            available = Math.min(nextX, nexty);

        } else if (d == ChessBoard.DIRECT.RIGHT) {
            nextX = x + 1;
            nexty = y;

            available = sizeClo - nextX;

        } else if (d == ChessBoard.DIRECT.RIGHT_BUTTON) {
            nextX = x + 1;
            nexty = y + 1;

            available = Math.min((sizeClo - nextX), (sizeClo - nexty));
        } else if (d == ChessBoard.DIRECT.TOP) {
            nextX = x;
            nexty = y - 1;

            available = nexty;

        } else if (d == ChessBoard.DIRECT.TOP_RIGHT) {
            // x+1 y-1
            nextX = x + 1;
            nexty = y - 1;

            available = Math.min((sizeClo - nextX), nexty);
        }

        if (!isAvailable(available, number)) {
            //LogUtils.d("无效 d=" + d + ",x,y,nextX,nextY" + x + "," + y + "," + nextX + "," + nexty);
            return 0;
        }

        int b = verfyNext(sizeRow, sizeClo, psrc, nextX, nexty, side);

        if (b == SAME) {
            //相同，继续迭代
            return verifyDirect(nextX, nexty, number, d, sizeRow, sizeClo, side);
        } else {
            //第一次加2 第二次加11，第三次加3，3
            deep += b;
        }

        return deep;
    }

    /**
     * 是否需要继续
     *
     * @param av
     * @param number
     * @return
     */
    private boolean isAvailable(int av, int number) {
        /**
         * 已有的连子，如果连到头还不够赢的话，则放弃这一条路,两连子以上才判断
         */
        if ((deep / N_STEP >= 2) && (deep / N_STEP + av) < number) {
            return false;
        }
        return true;
    }


    /**
     * 在某个位置放置一个棋子
     *
     * @param x
     * @param y
     * @param side
     */
    public void put(int x, int y, ChessBoard.SIDE side) {
        this.mResults[x][y].belong = side;
        this.mResults[x][y].x = x;
        this.mResults[x][y].y = y;
    }

    /**
     * 恢复在某个位置棋子
     *
     * @param x
     * @param y
     */
    public void del(int x, int y) {
        this.mResults[x][y].belong = ChessBoard.SIDE.NONE;
        this.mResults[x][y].x = PointU.P_UNUSE;
        this.mResults[x][y].y = PointU.P_UNUSE;
    }


}
